London bike Machine Learning project¶
- Projekt: Maschinelles Lernen mit Londoner Fahrradnutzungsdaten
- Ziel: Vorhersage zukünftiger Fahrradnutzungen
- Datenquellen: TfL Open Data, Wetterdaten von freemeteo.com, Feiertagsdaten von gov.uk
- Zeitraum der Daten: 04.01.2015 bis 03.01.2017
- Datengruppierung nach Startzeit, um die Anzahl neuer Fahrradnutzungen pro Stunde zu erfassen
- Berücksichtigung von Temperatur, Luftfeuchtigkeit, Windgeschwindigkeit, Wetterbedingungen, Feiertagen, Wochenenden und Jahreszeiten
- Lizenz von TfL Open Data erlaubt die Nutzung der Daten für kommerzielle und nicht-kommerzielle Zwecke unter bestimmten Bedingungen
- Ziel des Projekts: Verbesserung der Fahrradverteilung und -nutzung in London durch maschinelles Lernen und Datenanalyse.
import warnings
warnings.filterwarnings("ignore")
import pandas as pd
import numpy as np
import datetime
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold, cross_validate
from sklearn.model_selection import cross_val_score
import time
from sklearn.model_selection import cross_val_predict
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import Lasso
from sklearn.metrics import r2_score
from sklearn.metrics import (
make_scorer,
mean_squared_log_error,
mean_absolute_error,
mean_squared_error,
)
from sklearn.metrics import (
mean_squared_error,
mean_absolute_percentage_error,
)
from sklearn.metrics import make_scorer
from sklearn.metrics import max_error
from sklearn.ensemble import RandomForestRegressor, AdaBoostRegressor, BaggingRegressor
from sklearn.svm import SVR
from sklearn.model_selection import TimeSeriesSplit
from sklearn.model_selection import GridSearchCV
Section 1. Daten kennenlernen¶
Der Datensatz wurde in ein Pandas-Datenframe geladen.
df_bike = pd.read_csv("london_merged.csv")
df_bike.head()
| timestamp | cnt | t1 | t2 | hum | wind_speed | weather_code | is_holiday | is_weekend | season | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2015-01-04 00:00:00 | 182 | 3.0 | 2.0 | 93.0 | 6.0 | 3.0 | 0.0 | 1.0 | 3.0 |
| 1 | 2015-01-04 01:00:00 | 138 | 3.0 | 2.5 | 93.0 | 5.0 | 1.0 | 0.0 | 1.0 | 3.0 |
| 2 | 2015-01-04 02:00:00 | 134 | 2.5 | 2.5 | 96.5 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 |
| 3 | 2015-01-04 03:00:00 | 72 | 2.0 | 2.0 | 100.0 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 |
| 4 | 2015-01-04 04:00:00 | 47 | 2.0 | 0.0 | 93.0 | 6.5 | 1.0 | 0.0 | 1.0 | 3.0 |
Diese Daten enthalten historische Informationen über die Fahrradnutzung in London. Die Spalten in den Daten sind:
- timestamp: Der Zeitstempel für jede Stunde des Tages.
- cnt: Anzahl der geteilten Fahrräder.
- t1: Temperatur in Grad Celsius.
- t2: "Gefühlte" Temperatur in Grad Celsius.
- hum: Luftfeuchtigkeit.
- wind_speed: Windgeschwindigkeit.
- weather_code: Wettercode (1 für klares Wetter, 2 für teilweise bewölkt, 3 für etwas mehr bewölkt, 4 für bewölkt, 7 für Regen, 10 für Gewitter, 26 für Schnee).
- is_holiday: Ob es ein Feiertag ist oder nicht (1 = ja, 0 = nein).
- is_weekend: Ob es ein Wochenende ist oder nicht (1 = ja, 0 = nein).
- season: Jahreszeit (0 = Frühling, 1 = Sommer, 2 = Herbst, 3 = Winter).
df_bike.columns
Index(['timestamp', 'cnt', 't1', 't2', 'hum', 'wind_speed', 'weather_code',
'is_holiday', 'is_weekend', 'season'],
dtype='object')
df_bike.shape
(17414, 10)
print(
"Die Gesamtzahl der Datensätze im Datensatz beträgt: "
+ str(df_bike.timestamp.count())
+ ", from: "
+ str(df_bike.timestamp.min())
+ " to: "
+ str(df_bike.timestamp.max())
)
Die Gesamtzahl der Datensätze im Datensatz beträgt: 17414, from: 2015-01-04 00:00:00 to: 2017-01-03 23:00:00
df_bike.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 17414 entries, 0 to 17413 Data columns (total 10 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 timestamp 17414 non-null object 1 cnt 17414 non-null int64 2 t1 17414 non-null float64 3 t2 17414 non-null float64 4 hum 17414 non-null float64 5 wind_speed 17414 non-null float64 6 weather_code 17414 non-null float64 7 is_holiday 17414 non-null float64 8 is_weekend 17414 non-null float64 9 season 17414 non-null float64 dtypes: float64(8), int64(1), object(1) memory usage: 1.3+ MB
1.2 Data Cleaning¶
df_bike.rename(
columns={"cnt": "count", "t1": "temp", "t2": "temp_feels_like", "hum": "humidity"},
inplace=True,
)
df_bike["timestamp"] = pd.to_datetime(df_bike["timestamp"])
df_bike["year"] = df_bike["timestamp"].dt.year
df_bike["month"] = df_bike["timestamp"].dt.month_name()
df_bike["time"] = pd.to_datetime(df_bike["timestamp"]).dt.time
df_bike["day_of_week"] = df_bike["timestamp"].dt.day_name()
# تحويل رموز الفصول إلى أسماء
season_dict = {0.0: "Spring", 1.0: "Summer", 2.0: "Autumn", 3.0: "Winter"}
df_bike["season_name"] = df_bike["season"].map(season_dict)
df_bike["day"] = df_bike["timestamp"].dt.date
df_bike.describe()
| timestamp | count | temp | temp_feels_like | humidity | wind_speed | weather_code | is_holiday | is_weekend | season | year | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 17414 | 17414.000000 | 17414.000000 | 17414.000000 | 17414.000000 | 17414.000000 | 17414.000000 | 17414.000000 | 17414.000000 | 17414.000000 | 17414.000000 |
| mean | 2016-01-03 22:31:00.571953664 | 1143.101642 | 12.468091 | 11.520836 | 72.324954 | 15.913063 | 2.722752 | 0.022051 | 0.285403 | 1.492075 | 2015.507810 |
| min | 2015-01-04 00:00:00 | 0.000000 | -1.500000 | -6.000000 | 20.500000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 2015.000000 |
| 25% | 2015-07-04 20:15:00 | 257.000000 | 8.000000 | 6.000000 | 63.000000 | 10.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 2015.000000 |
| 50% | 2016-01-03 15:30:00 | 844.000000 | 12.500000 | 12.500000 | 74.500000 | 15.000000 | 2.000000 | 0.000000 | 0.000000 | 1.000000 | 2016.000000 |
| 75% | 2016-07-04 15:45:00 | 1671.750000 | 16.000000 | 16.000000 | 83.000000 | 20.500000 | 3.000000 | 0.000000 | 1.000000 | 2.000000 | 2016.000000 |
| max | 2017-01-03 23:00:00 | 7860.000000 | 34.000000 | 34.000000 | 100.000000 | 56.500000 | 26.000000 | 1.000000 | 1.000000 | 3.000000 | 2017.000000 |
| std | NaN | 1085.108068 | 5.571818 | 6.615145 | 14.313186 | 7.894570 | 2.341163 | 0.146854 | 0.451619 | 1.118911 | 0.508157 |
- count: Die Standardabweichung der Anzahl der geteilten Fahrräder beträgt 1085. Dies bedeutet, dass es große Schwankungen in der Anzahl der geteilten Fahrräder pro Stunde gibt. Dies könnte die sich ändernde Nachfrage nach Fahrrad-Sharing im Laufe des Tages widerspiegeln.
- temp und temp_feels_like: Die Standardabweichungen der Temperaturen (tatsächlich und "gefühlte") betragen etwa 5,5 bzw. 6,6 Grad Celsius. Dies spiegelt die natürlichen Temperaturschwankungen im Laufe des Tages und der Nacht wider.
- humidity: Die Standardabweichung der Luftfeuchtigkeit beträgt etwa 14,3, was auf Schwankungen in den Feuchtigkeitswerten hinweist.
- wind_speed: Die Standardabweichung der Windgeschwindigkeit beträgt etwa 7,9, was auf Schwankungen in den Windgeschwindigkeiten hinweist.
- weather_code: Die Standardabweichung des Wetters beträgt etwa 2,3, was auf Schwankungen in den Wetterbedingungen hinweist.
- is_holiday und is_weekend: Der Durchschnittswert dieser Spalten ist kleiner als 0,5, was darauf hindeut
من الجدول المستخرج من df_bike.describe()، يمكننا استخلاص النقاط التالية:
- cnt: الانحراف المعياري لعدد الدراجات المشتركة هو 1085. هذا يعني أن هناك تقلبات كبيرة في عدد الدراجات المشتركة في كل ساعة. هذا قد يعكس الطلب المتغير على مشاركة الدراجات خلال اليوم.
- t1 و t2: الانحراف المعياري لدرجات الحرارة (الفعلية و"الملموسة") هو حوالي 5.5 و6.6 على التوالي. هذا يعكس التقلبات الطبيعية في درجات الحرارة خلال اليوم والليل.
- hum: الانحراف المعياري لنسبة الرطوبة هو حوالي 14.3، مما يشير إلى تقلبات في مستويات الرطوبة.
- wind_speed: الانحراف المعياري لسرعة الرياح هو حوالي 7.9، مما يشير إلى تقلبات في سرعة الرياح.
- weather_code: الانحراف المعياري لرمز الطقس هو حوالي 2.3، مما يشير إلى تقلبات في ظروف الطقس.
- is_holiday و is_weekend: متوسط قيم هذه الأعمدة أقل من 0.5، مما يشير إلى أن معظم الأيام في البيانات ليست أيام عطلات أو نهاية أسبوع.
- season: متوسط قيم هذا العمود هو حوالي 1.5، مما يشير إلى أن معظم الأيام في البيانات تقع في فصول متأخرة من السنة (الصيف والخريف).
df_bike["timestamp"].value_counts()
timestamp
2015-01-04 00:00:00 1
2016-05-04 12:00:00 1
2016-05-04 18:00:00 1
2016-05-04 17:00:00 1
2016-05-04 16:00:00 1
..
2015-09-03 17:00:00 1
2015-09-03 18:00:00 1
2015-09-03 19:00:00 1
2015-09-03 20:00:00 1
2017-01-03 23:00:00 1
Name: count, Length: 17414, dtype: int64
Es gibt 17414 verschiedene timestamps, die jeweils nur einmal vorkommen. 17414/24/2 = 362.791666666666, das heißt es liegen durchschnittlich zu 362.8 Tagen pro Jahr Daten vor. Die Daten sind also fast vollständig.
df_bike["is_weekend"].value_counts()
is_weekend 0.0 12444 1.0 4970 Name: count, dtype: int64
df_bike["season"].value_counts()
season 0.0 4394 1.0 4387 3.0 4330 2.0 4303 Name: count, dtype: int64
Etwa 2/7 der Zeilen sind Wochenenden. Alle Jahreszeiten treten etwa gleich häufig auf. Das weist auf die Korrektheit der Daten hin. Die geringe Abweichung lässt sich durch die fehlenden Daten zu 2-3 Tagen pro Jahr erklären.
df_bike["weather_code"].value_counts()
weather_code 1.0 6150 2.0 4034 3.0 3551 7.0 2141 4.0 1464 26.0 60 10.0 14 Name: count, dtype: int64
Sonniges, bewölktes und regnerisches Wetter treten meistens auf. Gewitter und Schnee nur ziemlich selten.
df_bike["is_holiday"].value_counts()
is_holiday 0.0 17030 1.0 384 Name: count, dtype: int64
print("Feiertage pro Jahr: ~", 384 / 17414 * 365.25)
Feiertage pro Jahr: ~ 8.05420925691972
Section 2. Data visualization¶
df_bike.index = pd.to_datetime(df_bike["timestamp"])
agg_freq = "1W" # agg_freq = "1W": هذا يحدد التردد الذي سيتم استخدامه لتجميع البيانات. في هذه الحالة، “1W” يعني أن البيانات ستتم تجميعها بناءً على الأسبوع.
counts = (
df_bike["count"].groupby(pd.Grouper(freq=agg_freq)).sum()
) # عند استخدام pd.Grouper, يجب أن يكون الفهرس من نوع DatetimeIndex لأن pd.Grouper يقوم بتجميع البيانات بناءً على التواريخ
temps = (
df_bike["temp"].groupby(pd.Grouper(freq=agg_freq)).mean()
) # هذا يقوم بتجميع درجات الحرارة (“t1”) بناءً على التردد الذي حددناه ويحسب المتوسط لكل أسبوع.
hums = df_bike["humidity"].groupby(pd.Grouper(freq=agg_freq)).mean()
winds = df_bike["wind_speed"].groupby(pd.Grouper(freq=agg_freq)).mean()
fig, axes = plt.subplots(4, 1)
fig.set_figheight(12)
fig.set_figwidth(12)
axes[0].set_title("Bike shares")
sns.lineplot(x=counts.index, y=counts.values, ax=axes[0], color="green")
axes[1].set_title("Temperature")
sns.lineplot(x=temps.index, y=temps.values, ax=axes[1], color="green")
axes[2].set_title("Humidity")
sns.lineplot(x=hums.index, y=hums.values, ax=axes[2], color="green")
axes[3].set_title("Wind speed")
sns.lineplot(x=winds.index, y=winds.values, ax=axes[3], color="green")
plt.tight_layout()
Aus den Diagrammen können wir folgende Punkte ableiten:
- Fahrradfreigabe: Es scheint ein saisonales Muster für die Fahrradfreigabe zu geben, mit einer Zunahme der Nachfrage in den wärmeren Monaten und einem Rückgang in den kälteren Monaten. Dies spiegelt die Auswirkungen des Wetters auf die Fahrradfreigabe wider.
- Temperatur: Die Temperaturen folgen einem erwarteten saisonalen Muster, mit steigenden Temperaturen im Sommer und fallenden Temperaturen im Winter.
- Feuchtigkeit: Es scheint einen allgemeinen Trend zu einer Zunahme der Feuchtigkeit im Laufe des Jahres zu geben, mit einigen saisonalen Schwankungen.
- Windgeschwindigkeit: Es gibt kein klares Muster für die Windgeschwindigkeit, aber es scheint einige saisonale Schwankungen zu geben.
من الرسوم البيانية، يمكننا استخلاص النقاط التالية:
- مشاركة الدراجات: يبدو أن هناك نمطًا موسميًا لمشاركة الدراجات، مع زيادة في الطلب خلال الأشهر الأكثر دفئًا وانخفاض خلال الأشهر الأكثر برودة. هذا يعكس تأثير الطقس على مشاركة الدراجات.
- الحرارة: تتبع درجات الحرارة نمطًا موسميًا متوقعًا، مع ارتفاع درجات الحرارة في فصل الصيف وانخفاضها في فصل الشتاء.
- الرطوبة: يبدو أن هناك اتجاهًا عامًا نحو زيادة الرطوبة على مدار العام، مع بعض التقلبات الموسمية.
- سرعة الرياح: ليست هناك أي نمط واضح لسرعة الرياح، لكن يبدو أن هناك بعض التقلبات الموسمية.
Korrelationen in Wetterdaten:¶
Um ein besseres Verständnis der statistischen Eigenschaften der Wetterdaten zu erhalten, wird ein paarweiser Multi-Streuungsplot erstellt. Hier kann festgestellt werden, dass es eine starke Korrelation zwischen der realen Temperatur (temp_real) und der gefühlten Temperatur (temp_feels) gibt, während die anderen Variablen höchstens schwach korreliert sind. Daher könnten alle interessant sein, um weiter untersucht zu werden.
"الارتباطات في بيانات الطقس للحصول على فهم أفضل للخصائص الإحصائية لبيانات الطقس، يتم إنشاء رسم بياني متعدد للنقاط الزوجية. هنا يمكن ملاحظة أنه بينما هناك ارتباط قوي بين درجة الحرارة الحقيقية (temp_real) ودرجة الحرارة المحسوسة (temp_feels)، فإن المتغيرات الأخرى مرتبطة ضعيفة على الأكثر. وبالتالي، قد يكون من المثير للاهتمام التحقيق فيها جميعًا."
mean_agg = (
df_bike[["temp", "temp_feels_like", "humidity", "wind_speed", "season"]]
.groupby(pd.Grouper(freq=agg_freq))
.mean()
)
season_key = ["Spring", "Summer", "Autumn", "Winter"]
seasons = (
mean_agg["season"]
.apply(lambda x: int(np.floor(x)))
.apply(
lambda x: season_key[x]
) # هذا يقوم بتحويل قيم الموسم في mean_agg من أرقام إلى أسماء الفصول باستخدام season_key. يتم تخزين النتائج في seasons.
)
mean_agg["season"] = seasons
g = sns.PairGrid(mean_agg, hue="season")
g.map_diag(sns.histplot)
g.map_offdiag(sns.scatterplot)
g.add_legend()
<seaborn.axisgrid.PairGrid at 0x1fba013d2d0>
Korrelationen zwischen der Nutzung von Fahrrädern und Wetterdaten:¶
Mögliche Korrelationen zwischen Wetterdaten und aggregierter Fahrradnutzung (unter Verwendung derselben Zeitintervalle wie in den vorherigen Abschnitten) werden untersucht.
weather_counts = mean_agg[["temp", "humidity", "wind_speed", "season"]].join(counts)
weather_counts
| temp | humidity | wind_speed | season | count | |
|---|---|---|---|---|---|
| timestamp | |||||
| 2015-01-04 | 2.479167 | 94.270833 | 7.500000 | Winter | 9234 |
| 2015-01-11 | 9.002994 | 75.008982 | 22.715569 | Winter | 129038 |
| 2015-01-18 | 6.863095 | 73.092262 | 20.619048 | Winter | 139559 |
| 2015-01-25 | 3.434524 | 78.604167 | 11.922619 | Winter | 146866 |
| 2015-02-01 | 5.351190 | 73.446429 | 21.761905 | Winter | 133247 |
| ... | ... | ... | ... | ... | ... |
| 2016-12-11 | 9.886905 | 87.479167 | 12.470238 | Winter | 174112 |
| 2016-12-18 | 9.187500 | 90.505952 | 8.985119 | Winter | 168680 |
| 2016-12-25 | 9.062500 | 81.613095 | 17.470238 | Winter | 151948 |
| 2017-01-01 | 5.169643 | 88.250000 | 11.345238 | Winter | 78188 |
| 2017-01-08 | 3.562500 | 82.270833 | 15.052083 | Winter | 31259 |
106 rows × 5 columns
g = sns.PairGrid(
weather_counts,
x_vars=[
"temp",
"humidity",
"wind_speed",
],
y_vars="count",
hue="season",
height=5,
# palette="pastel",
)
g.map(sns.scatterplot)
g.add_legend()
<seaborn.axisgrid.PairGrid at 0x1fba4487d90>
Aus dem Diagramm können wir folgende Punkte ableiten:
- Temperatur (t1): Es scheint eine positive Korrelation zwischen der Temperatur und der Anzahl der geteilten Fahrräder zu geben. Das bedeutet, dass normalerweise, wenn die Temperatur steigt, die Anzahl der geteilten Fahrräder ebenfalls steigt.
- Feuchtigkeit (hum): Es scheint eine negative Korrelation zwischen der Feuchtigkeit und der Anzahl der geteilten Fahrräder zu geben. Das bedeutet, dass normalerweise, wenn die Feuchtigkeit steigt, die Anzahl der geteilten Fahrräder abnimmt.
- Windgeschwindigkeit (wind_speed): Es scheint keine klare Korrelation zwischen der Windgeschwindigkeit und der Anzahl der geteilten Fahrräder zu geben. Dies könnte darauf hindeuten, dass die Windgeschwindigkeit keinen großen Einfluss auf das Fahrrad-Sharing hat.
- Jahreszeit (season): Der Wechsel der Punktfarben zeigt, dass es saisonale Unterschiede in allen Variablen gibt. Zum Beispiel können Sie in dem Diagramm von t1 gegen cnt verschiedene farbige Punkte sehen, was darauf hindeutet, dass die Anzahl der geteilten Fahrräder je nach Jahreszeit variiert.
من الرسم البياني، يمكننا استخلاص النقاط التالية:
- الحرارة (t1): يبدو أن هناك ارتباطًا إيجابيًا بين درجة الحرارة وعدد الدراجات المشتركة. هذا يعني أنه عندما ترتفع درجة الحرارة، يزداد عدد الدراجات المشتركة عادة.
- الرطوبة (hum): يبدو أن هناك ارتباطًا سلبيًا بين الرطوبة وعدد الدراجات المشتركة. هذا يعني أنه عندما تزداد الرطوبة، يقل عدد الدراجات المشتركة عادة.
- سرعة الرياح (wind_speed): لا يبدو أن هناك ارتباطًا واضحًا بين سرعة الرياح وعدد الدراجات المشتركة. هذا قد يشير إلى أن سرعة الرياح ليست عاملاً رئيسيًا في تأثير مشاركة الدراجات.
- الموسم (season): يظهر التغير في لون النقاط أن هناك فروقات موسمية في جميع المتغيرات. على سبيل المثال، يمكن رؤية نقاط مختلفة في لونها في رسم t1 ضد cnt، مما يشير إلى أن عدد الدراجات المشتركة يختلف مع المواسم.
df_bike = df_bike.reset_index(drop=True)
# تعيين حجم الرسم والدقة
plt.figure(figsize=(20, 5), dpi=300)
# إنشاء الرسم البياني لتوزيع عدد ركوب الدراجات
sns.distplot(df_bike["count"])
# تعيين العنوان باللغة الألمانية
plt.title("Verteilung der Fahrradfahrten", fontsize=20)
# إزالة الحواف العلوية واليمنى من الرسم البياني
sns.despine(top=True)
# إضافة خط متوسط القيمة بشكل متقطع
mean_count = df_bike["count"].mean()
plt.axvline(mean_count, ls="--", color="red", label=f"Mittelwert: {mean_count:.2f}")
plt.legend()
# إظهار الرسم البياني
plt.show()
Im obigen Diagramm ist zu erkennen, dass zu bestimmten Zeiten eine große Anzahl von Fahrrädern gleichzeitig geteilt wird (mehr als 4.800 Fahrräder). Solche Phänomene sind sehr selten, und Daten, die sich auf sie beziehen, sollten als Ausreißer betrachtet und daher vor dem Training eines Modells entfernt werden.
Bevor Daten aus dem Datensatz entfernt werden, sollte festgestellt werden, ob solche Anomalien mit bestimmten Tagen oder Ereignissen zusammenhängen (Datenanalyse).
plt.figure(figsize=(20, 5), dpi=300)
sns.histplot(data=df_bike, x="temp", kde=True, color="skyblue")
plt.axvline(
df_bike["temp"].mean(),
ls="--",
color="red",
label=f'Durchschnittliche Temperatur: {df_bike["temp"].mean():.2f}',
)
# Festlegen des Titels und der Achsenbeschriftungen auf Deutsch
plt.title("Verteilung der tatsächlichen Temperatur", fontsize=6)
plt.xlabel("Tatsächliche Temperatur")
plt.ylabel("Anzahl der Datensätze")
# Anzeigen der Legende und des Diagramms
plt.legend()
plt.show()
plt.figure(figsize=(20, 5), dpi=300)
sns.histplot(data=df_bike, x="temp_feels_like", kde=True, color="skyblue")
plt.axvline(
df_bike["temp_feels_like"].mean(),
ls="--",
color="red",
label=f'Durchschnittliche Temperatur: {df_bike["temp_feels_like"].mean():.2f}',
)
# Festlegen des Titels und der Achsenbeschriftungen auf Deutsch
plt.title("Verteilung der gefühlten Temperatur", fontsize=6)
plt.xlabel("Gefühlte Temperatur")
plt.ylabel("Anzahl der Datensätze")
# Anzeigen der Legende und des Diagramms
plt.legend()
plt.show()
Die Grafik der tatsächlichen Temperatur ist entspricht annähernd einer Normalverteilung. Die Grafik der gefühlten Temperatur entspricht teilweise auch einer Normalverteilung, wobei im Bereich zwischen 6 und 12 °C ein Einbruch vorliegt. Es ist unklar, warum eine gefühlte Temperatur in diesem Bereich seltener vorkommt. Die sehr fluktuierende Höhe der Balken lässt sich dadurch erklären, dass ganzzahlige Temperaturen deutlich häufiger vorkommen als Temperaturen wie "10,5" oder "11,5". Wahrscheinlich werden einige Temperaturen in den Wetterdaten auf ganzzahlige Werte gerundet.
plt.figure(figsize=(20, 5), dpi=300)
fig = sns.distplot(df_bike["humidity"])
plt.xlabel("", fontsize=15)
plt.title("Distribution of Humidity", fontsize=20)
sns.despine(top=True)
plt.axvline(df_bike["humidity"].mean(), ls="--")
<matplotlib.lines.Line2D at 0x1fba4fc1650>
plt.figure(figsize=(20, 5), dpi=300)
fig = sns.barplot(data=df_bike, x="time", y="count", palette="deep")
plt.xlabel("Zeit", fontsize=15)
plt.ylabel("Anzahl der Fahrradfahrten", fontsize=15)
plt.title("Verbreitung der Fahrradfahrten nach Tageszeit", fontsize=20)
sns.despine(top=True)
plt.axhline(df_bike["count"].sum() / len(df_bike), ls="--")
<matplotlib.lines.Line2D at 0x1fba7baf210>
plt.figure(figsize=(20, 5), dpi=300)
fig = sns.barplot(data=df_bike, x="time", y="count", hue="is_holiday", palette="deep")
plt.xlabel("Time", fontsize=15)
plt.ylabel("No. of Bike Rides", fontsize=15)
plt.title("Bike rides spread according to weekends/holidays and weekdays", fontsize=20)
sns.despine(top=True)
plt.axhline(df_bike["count"].sum() / len(df_bike), ls="--")
<matplotlib.lines.Line2D at 0x1fba99d9650>
df_bike
| timestamp | count | temp | temp_feels_like | humidity | wind_speed | weather_code | is_holiday | is_weekend | season | year | month | time | day_of_week | season_name | day | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2015-01-04 00:00:00 | 182 | 3.0 | 2.0 | 93.0 | 6.0 | 3.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 00:00:00 | Sunday | Winter | 2015-01-04 |
| 1 | 2015-01-04 01:00:00 | 138 | 3.0 | 2.5 | 93.0 | 5.0 | 1.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 01:00:00 | Sunday | Winter | 2015-01-04 |
| 2 | 2015-01-04 02:00:00 | 134 | 2.5 | 2.5 | 96.5 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 02:00:00 | Sunday | Winter | 2015-01-04 |
| 3 | 2015-01-04 03:00:00 | 72 | 2.0 | 2.0 | 100.0 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 03:00:00 | Sunday | Winter | 2015-01-04 |
| 4 | 2015-01-04 04:00:00 | 47 | 2.0 | 0.0 | 93.0 | 6.5 | 1.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 04:00:00 | Sunday | Winter | 2015-01-04 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 17409 | 2017-01-03 19:00:00 | 1042 | 5.0 | 1.0 | 81.0 | 19.0 | 3.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 19:00:00 | Tuesday | Winter | 2017-01-03 |
| 17410 | 2017-01-03 20:00:00 | 541 | 5.0 | 1.0 | 81.0 | 21.0 | 4.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 20:00:00 | Tuesday | Winter | 2017-01-03 |
| 17411 | 2017-01-03 21:00:00 | 337 | 5.5 | 1.5 | 78.5 | 24.0 | 4.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 21:00:00 | Tuesday | Winter | 2017-01-03 |
| 17412 | 2017-01-03 22:00:00 | 224 | 5.5 | 1.5 | 76.0 | 23.0 | 4.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 22:00:00 | Tuesday | Winter | 2017-01-03 |
| 17413 | 2017-01-03 23:00:00 | 139 | 5.0 | 1.0 | 76.0 | 22.0 | 2.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 23:00:00 | Tuesday | Winter | 2017-01-03 |
17414 rows × 16 columns
plt.figure(figsize=(20, 5), dpi=300)
fig = sns.barplot(data=df_bike, x="month", y="count", palette="deep")
plt.xlabel("Monat", fontsize=15)
plt.ylabel("Anzahl der Fahrradfahrten", fontsize=15)
plt.title("Verteilung der Fahrradfahrten über das Jahr", fontsize=20)
# إزالة الحواف العلوية
sns.despine(top=True)
# إضافة خط للقيمة المتوسطة
plt.axhline(df_bike["count"].sum() / len(df_bike), ls="--")
# إظهار الرسم البياني
plt.show()
plt.figure(figsize=(20, 5), dpi=300)
# إنشاء الرسم البياني
fig = sns.barplot(
data=df_bike,
x="day_of_week",
y="count",
palette="deep",
order=[
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
],
)
# تعيين التسميات
plt.xlabel("Tag der Woche", fontsize=15)
plt.ylabel("Anzahl der Fahrradfahrten", fontsize=15)
plt.title("Verteilung der Fahrradfahrten über die Woche", fontsize=20)
# إزالة الحواف العلوية
sns.despine(top=True)
# إضافة خط للقيمة المتوسطة
plt.axhline(df_bike["count"].sum() / len(df_bike), ls="--")
# إظهار الرسم البياني
plt.show()
plt.figure(figsize=(20, 5), dpi=300)
# إنشاء الرسم البياني
fig = sns.barplot(
data=df_bike,
x="season_name",
y="count",
palette="deep",
)
# تعيين التسميات
plt.xlabel("Jahreszeit", fontsize=15)
plt.ylabel("Anzahl der Fahrradfahrten", fontsize=15)
plt.title("Verteilung der Fahrradfahrten nach Jahreszeiten", fontsize=20)
# إزالة الحواف العلوية
sns.despine(top=True)
# إضافة خط للقيمة المتوسطة
plt.axhline(df_bike["count"].sum() / len(df_bike), ls="--")
# إظهار الرسم البياني
plt.show()
plt.figure(figsize=(20, 5), dpi=300)
fig = sns.lineplot(data=df_bike, x="temp_feels_like", y="count")
plt.xlabel("Temperatur", fontsize=15)
plt.ylabel("Anzahl der Fahrradfahrten", fontsize=15)
plt.title("Beziehung zwischen Temperatur und Fahrradfahrten", fontsize=20)
sns.despine(top=True)
plt.axhline(df_bike["count"].sum() / len(df_bike), ls="--")
<matplotlib.lines.Line2D at 0x1fba9b82cd0>
Das Durchschnittnehmen der gemeinsam genutzten Fahrräder bei verschiedenen Temperaturaufzeichnungen scheint eine positive Korrelation zwischen beiden Attributen zu zeigen. Die Berechnung der Korrelation zwischen der Anzahl der gemeinsam genutzten Fahrräder und der Temperatur wäre nützlich, um eine solche Hypothese zu überprüfen.
plt.figure(figsize=(20, 5), dpi=300)
fig = sns.lineplot(data=df_bike, x="humidity", y="count")
plt.xlabel("Luftfeuchtigkeit", fontsize=15)
plt.ylabel("Anzahl der Fahrradfahrten", fontsize=15)
plt.title("Beziehung zwischen Luftfeuchtigkeit und Fahrradfahrten", fontsize=20)
sns.despine(top=True)
plt.axhline(df_bike["count"].sum() / len(df_bike), ls="--")
<matplotlib.lines.Line2D at 0x1fba9d31050>
Im Gegensatz zur Temperatur zeigt die Luftfeuchtigkeit eine negative Korrelation mit der Anzahl der gemeinsam genutzten Fahrräder, was bedeutet, dass bei höherer Luftfeuchtigkeit weniger Fahrräder gemeinsam genutzt werden. Dies hängt wahrscheinlich mit Regen zusammen, denn niemand möchte beim Fahrradfahren nass werden.
plt.figure(figsize=(20, 5), dpi=300)
fig = sns.lineplot(data=df_bike, x="wind_speed", y="count")
plt.xlabel("Windgeschwindigkeit", fontsize=15)
plt.ylabel("Anzahl der Fahrradfahrten", fontsize=15)
plt.title("Beziehung zwischen Windgeschwindigkeit und Fahrradfahrten", fontsize=20)
sns.despine(top=True)
plt.axhline(df_bike["count"].sum() / len(df_bike), ls="--")
<matplotlib.lines.Line2D at 0x1fba9b21dd0>
Es gibt keine klare Korrelation zwischen der Anzahl der gemeinsam genutzten Fahrräder und der Windgeschwindigkeit. Offensichtlich sinkt die Anzahl der gemeinsam genutzten Fahrräder, wenn die Windgeschwindigkeit abnimmt, und dasselbe passiert, wenn die Windgeschwindigkeit zunimmt. Möglicherweise kann ein hoher Korrelationswert durch eine nicht-lineare Korrelationsmethode (wie Spearman) gefunden werden.
Section 3. Data analysis¶
df_bike.isna().sum()
timestamp 0 count 0 temp 0 temp_feels_like 0 humidity 0 wind_speed 0 weather_code 0 is_holiday 0 is_weekend 0 season 0 year 0 month 0 time 0 day_of_week 0 season_name 0 day 0 dtype: int64
# إنشاء مؤشر لساعة كل صف
hourly_counts = df_bike[df_bike["count"] > 4000].groupby(df_bike["time"]).size()
# عرض النتائج
print(hourly_counts)
time 07:00:00 2 08:00:00 273 09:00:00 1 13:00:00 3 14:00:00 3 15:00:00 6 16:00:00 5 17:00:00 120 18:00:00 99 19:00:00 2 dtype: int64
Wenn man die vorherige Tabelle betrachtet, kann man feststellen, dass die Einträge mit den höchsten Bereichen von geteilten Fahrrädern auf bestimmte Tageszeiten (7:00 - 8:00 Uhr, 17:00 - 18:00 Uhr) bezogen sind, wahrscheinlich die Zeiten, zu denen die Londoner normalerweise zur Schule/Arbeit und nach Hause gehen.
df_bike
| timestamp | count | temp | temp_feels_like | humidity | wind_speed | weather_code | is_holiday | is_weekend | season | year | month | time | day_of_week | season_name | day | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2015-01-04 00:00:00 | 182 | 3.0 | 2.0 | 93.0 | 6.0 | 3.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 00:00:00 | Sunday | Winter | 2015-01-04 |
| 1 | 2015-01-04 01:00:00 | 138 | 3.0 | 2.5 | 93.0 | 5.0 | 1.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 01:00:00 | Sunday | Winter | 2015-01-04 |
| 2 | 2015-01-04 02:00:00 | 134 | 2.5 | 2.5 | 96.5 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 02:00:00 | Sunday | Winter | 2015-01-04 |
| 3 | 2015-01-04 03:00:00 | 72 | 2.0 | 2.0 | 100.0 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 03:00:00 | Sunday | Winter | 2015-01-04 |
| 4 | 2015-01-04 04:00:00 | 47 | 2.0 | 0.0 | 93.0 | 6.5 | 1.0 | 0.0 | 1.0 | 3.0 | 2015 | January | 04:00:00 | Sunday | Winter | 2015-01-04 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 17409 | 2017-01-03 19:00:00 | 1042 | 5.0 | 1.0 | 81.0 | 19.0 | 3.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 19:00:00 | Tuesday | Winter | 2017-01-03 |
| 17410 | 2017-01-03 20:00:00 | 541 | 5.0 | 1.0 | 81.0 | 21.0 | 4.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 20:00:00 | Tuesday | Winter | 2017-01-03 |
| 17411 | 2017-01-03 21:00:00 | 337 | 5.5 | 1.5 | 78.5 | 24.0 | 4.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 21:00:00 | Tuesday | Winter | 2017-01-03 |
| 17412 | 2017-01-03 22:00:00 | 224 | 5.5 | 1.5 | 76.0 | 23.0 | 4.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 22:00:00 | Tuesday | Winter | 2017-01-03 |
| 17413 | 2017-01-03 23:00:00 | 139 | 5.0 | 1.0 | 76.0 | 22.0 | 2.0 | 0.0 | 0.0 | 3.0 | 2017 | January | 23:00:00 | Tuesday | Winter | 2017-01-03 |
17414 rows × 16 columns
df_bike[df_bike["count"] > 4000].sort_values(by=["count"]).tail()
| timestamp | count | temp | temp_feels_like | humidity | wind_speed | weather_code | is_holiday | is_weekend | season | year | month | time | day_of_week | season_name | day | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 5129 | 2015-08-06 08:00:00 | 6585 | 19.0 | 19.0 | 78.0 | 12.0 | 7.0 | 0.0 | 0.0 | 1.0 | 2015 | August | 08:00:00 | Thursday | Summer | 2015-08-06 |
| 4471 | 2015-07-09 18:00:00 | 6913 | 22.5 | 21.5 | 29.0 | 13.0 | 1.0 | 0.0 | 0.0 | 1.0 | 2015 | July | 18:00:00 | Thursday | Summer | 2015-07-09 |
| 5138 | 2015-08-06 17:00:00 | 7208 | 22.5 | 22.5 | 55.0 | 17.5 | 2.0 | 0.0 | 0.0 | 1.0 | 2015 | August | 17:00:00 | Thursday | Summer | 2015-08-06 |
| 4461 | 2015-07-09 08:00:00 | 7531 | 14.5 | 14.5 | 61.0 | 19.0 | 2.0 | 0.0 | 0.0 | 1.0 | 2015 | July | 08:00:00 | Thursday | Summer | 2015-07-09 |
| 4470 | 2015-07-09 17:00:00 | 7860 | 23.0 | 22.0 | 27.0 | 11.0 | 1.0 | 0.0 | 0.0 | 1.0 | 2015 | July | 17:00:00 | Thursday | Summer | 2015-07-09 |
"Vielleicht handelt es sich bei diesen Daten um Ereignisse in London, und daher sind sie als Ausreißer zu betrachten, die gelöscht werden sollten. Es muss überprüft werden."
# pd.set_option("display.max_rows", None)
share_bikes = df_bike
share_bikes = share_bikes.groupby(
[
"day",
"month",
"is_holiday",
"is_weekend",
],
as_index=False,
)["count"].sum()
mean_day = share_bikes["count"].mean()
print("The mean of shared bikes per day is: " + str(mean_day))
The mean of shared bikes per day is: 27268.45479452055
share_bikes[share_bikes["count"] < mean_day][
["day", "month", "count", "is_holiday", "is_weekend"]
].sort_values(by=["count"])
| day | month | count | is_holiday | is_weekend | |
|---|---|---|---|---|---|
| 364 | 2016-01-03 | January | 4869 | 0.0 | 1.0 |
| 727 | 2017-01-01 | January | 6421 | 0.0 | 1.0 |
| 363 | 2016-01-02 | January | 7195 | 0.0 | 1.0 |
| 719 | 2016-12-24 | December | 7890 | 0.0 | 1.0 |
| 448 | 2016-03-27 | March | 8123 | 0.0 | 1.0 |
| ... | ... | ... | ... | ... | ... |
| 438 | 2016-03-17 | March | 27060 | 0.0 | 0.0 |
| 453 | 2016-04-01 | April | 27137 | 0.0 | 0.0 |
| 197 | 2015-07-20 | July | 27163 | 0.0 | 0.0 |
| 621 | 2016-09-17 | September | 27182 | 0.0 | 1.0 |
| 460 | 2016-04-08 | April | 27191 | 0.0 | 0.0 |
372 rows × 5 columns
Offensichtlich sind niedrige Fahrradzahlen während der letzten und ersten Wochenenden und Feiertage des Jahres sehr häufig. Dies erklärt die negativen Ausreißer, die tatsächlich während des Trainings des Vorhersagemodells berücksichtigt werden sollten.
على ما يبدو، فإن النطاقات المنخفضة للدراجات المشتركة شائعة جدًا خلال عطلات نهاية الأسبوع والأعياد الأولى من العام. وهذا ما يفسر القيم المتطرفة السلبية، والتي ينبغي أخذها في الاعتبار فعليًا أثناء تدريب النموذج التنبؤي.
3.1 Correlation between attributes¶
df_corr = df_bike.corr(method="pearson", numeric_only=True)
df_corr
| count | temp | temp_feels_like | humidity | wind_speed | weather_code | is_holiday | is_weekend | season | year | |
|---|---|---|---|---|---|---|---|---|---|---|
| count | 1.000000 | 0.388798 | 0.369035 | -0.462901 | 0.116295 | -0.166633 | -0.051698 | -0.096499 | -0.116180 | 0.010046 |
| temp | 0.388798 | 1.000000 | 0.988344 | -0.447781 | 0.145471 | -0.097114 | -0.042233 | -0.005342 | -0.285851 | -0.037959 |
| temp_feels_like | 0.369035 | 0.988344 | 1.000000 | -0.403495 | 0.088409 | -0.098385 | -0.040051 | -0.008510 | -0.285900 | -0.044972 |
| humidity | -0.462901 | -0.447781 | -0.403495 | 1.000000 | -0.287789 | 0.334750 | 0.032068 | 0.028098 | 0.290381 | 0.072443 |
| wind_speed | 0.116295 | 0.145471 | 0.088409 | -0.287789 | 1.000000 | 0.124803 | -0.002606 | 0.011479 | 0.010305 | -0.094739 |
| weather_code | -0.166633 | -0.097114 | -0.098385 | 0.334750 | 0.124803 | 1.000000 | 0.012939 | 0.042362 | 0.098976 | -0.009234 |
| is_holiday | -0.051698 | -0.042233 | -0.040051 | 0.032068 | -0.002606 | 0.012939 | 1.000000 | -0.094898 | -0.032488 | 0.034631 |
| is_weekend | -0.096499 | -0.005342 | -0.008510 | 0.028098 | 0.011479 | 0.042362 | -0.094898 | 1.000000 | 0.001067 | 0.003049 |
| season | -0.116180 | -0.285851 | -0.285900 | 0.290381 | 0.010305 | 0.098976 | -0.032488 | 0.001067 | 1.000000 | 0.024400 |
| year | 0.010046 | -0.037959 | -0.044972 | 0.072443 | -0.094739 | -0.009234 | 0.034631 | 0.003049 | 0.024400 | 1.000000 |
cmap = sns.diverging_palette(220, 10, as_cmap=True)
sns.heatmap(
df_bike.corr(method="pearson", numeric_only=True),
cmap=cmap,
vmax=1.0,
vmin=-1.0,
center=0,
square=True,
linewidths=0.5,
)
plt.title("Correlation between attributes")
Text(0.5, 1.0, 'Correlation between attributes')
Wie aus der Korrelationsmatrix ersichtlich ist, sind die oben gemachten Beobachtungen korrekt. Die Anzahl der gemeinsam genutzten Fahrräder (count) korreliert positiv mit der Temperatur (temp) und negativ mit der Luftfeuchtigkeit (humidity).
Abschnitt 4. Datenverarbeitung¶
df_bike["n_day"] = pd.to_numeric(df_bike["timestamp"].dt.strftime("%d"))
df_bike["n_month"] = df_bike["timestamp"].dt.month
df_bike["n_hour"] = df_bike["timestamp"].dt.hour
df_bike["n_day_of_week"] = df_bike["timestamp"].dt.dayofweek
df_bike["n_day_of_year"] = df_bike["timestamp"].dt.dayofyear
df_bike.tail()
| timestamp | count | temp | temp_feels_like | humidity | wind_speed | weather_code | is_holiday | is_weekend | season | ... | month | time | day_of_week | season_name | day | n_day | n_month | n_hour | n_day_of_week | n_day_of_year | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 17409 | 2017-01-03 19:00:00 | 1042 | 5.0 | 1.0 | 81.0 | 19.0 | 3.0 | 0.0 | 0.0 | 3.0 | ... | January | 19:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 19 | 1 | 3 |
| 17410 | 2017-01-03 20:00:00 | 541 | 5.0 | 1.0 | 81.0 | 21.0 | 4.0 | 0.0 | 0.0 | 3.0 | ... | January | 20:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 20 | 1 | 3 |
| 17411 | 2017-01-03 21:00:00 | 337 | 5.5 | 1.5 | 78.5 | 24.0 | 4.0 | 0.0 | 0.0 | 3.0 | ... | January | 21:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 21 | 1 | 3 |
| 17412 | 2017-01-03 22:00:00 | 224 | 5.5 | 1.5 | 76.0 | 23.0 | 4.0 | 0.0 | 0.0 | 3.0 | ... | January | 22:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 22 | 1 | 3 |
| 17413 | 2017-01-03 23:00:00 | 139 | 5.0 | 1.0 | 76.0 | 22.0 | 2.0 | 0.0 | 0.0 | 3.0 | ... | January | 23:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 23 | 1 | 3 |
5 rows × 21 columns
# df_bike["cnt_log"] = np.log1p(df_bike["count"])
""" sns.distplot(df_bike["cnt_log"])
plt.title("Histogram of logarithm of count of shared bikes")
plt.ylabel("Density") """
' sns.distplot(df_bike["cnt_log"])\nplt.title("Histogram of logarithm of count of shared bikes")\nplt.ylabel("Density") '
4.2. Removing outliers¶
import matplotlib.pyplot as plt
# تعيين حجم الرسم والدقة
plt.figure(figsize=(6, 3), dpi=100)
# رسم البيانات
plt.plot(
df_bike["timestamp"],
df_bike["count"],
color="orange",
marker="o",
linestyle="-",
linewidth=1,
markersize=3,
)
plt.title("Anzahl der Fahrräder nach Datum", fontsize=16)
plt.xlabel("Datum", fontsize=12)
plt.ylabel("Geteilte Fahrräder", fontsize=12)
plt.grid(True, linestyle="--", alpha=0.6)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
outliers = df_bike[df_bike["count"] > 6000]
outliers
| timestamp | count | temp | temp_feels_like | humidity | wind_speed | weather_code | is_holiday | is_weekend | season | ... | month | time | day_of_week | season_name | day | n_day | n_month | n_hour | n_day_of_week | n_day_of_year | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 4461 | 2015-07-09 08:00:00 | 7531 | 14.5 | 14.5 | 61.0 | 19.0 | 2.0 | 0.0 | 0.0 | 1.0 | ... | July | 08:00:00 | Thursday | Summer | 2015-07-09 | 9 | 7 | 8 | 3 | 190 |
| 4469 | 2015-07-09 16:00:00 | 6033 | 23.0 | 22.0 | 26.0 | 11.0 | 1.0 | 0.0 | 0.0 | 1.0 | ... | July | 16:00:00 | Thursday | Summer | 2015-07-09 | 9 | 7 | 16 | 3 | 190 |
| 4470 | 2015-07-09 17:00:00 | 7860 | 23.0 | 22.0 | 27.0 | 11.0 | 1.0 | 0.0 | 0.0 | 1.0 | ... | July | 17:00:00 | Thursday | Summer | 2015-07-09 | 9 | 7 | 17 | 3 | 190 |
| 4471 | 2015-07-09 18:00:00 | 6913 | 22.5 | 21.5 | 29.0 | 13.0 | 1.0 | 0.0 | 0.0 | 1.0 | ... | July | 18:00:00 | Thursday | Summer | 2015-07-09 | 9 | 7 | 18 | 3 | 190 |
| 5129 | 2015-08-06 08:00:00 | 6585 | 19.0 | 19.0 | 78.0 | 12.0 | 7.0 | 0.0 | 0.0 | 1.0 | ... | August | 08:00:00 | Thursday | Summer | 2015-08-06 | 6 | 8 | 8 | 3 | 218 |
| 5138 | 2015-08-06 17:00:00 | 7208 | 22.5 | 22.5 | 55.0 | 17.5 | 2.0 | 0.0 | 0.0 | 1.0 | ... | August | 17:00:00 | Thursday | Summer | 2015-08-06 | 6 | 8 | 17 | 3 | 218 |
| 5139 | 2015-08-06 18:00:00 | 6394 | 21.5 | 21.5 | 58.5 | 20.0 | 2.0 | 0.0 | 0.0 | 1.0 | ... | August | 18:00:00 | Thursday | Summer | 2015-08-06 | 6 | 8 | 18 | 3 | 218 |
7 rows × 21 columns
df_bike = df_bike.drop(outliers.index)
# تعيين حجم الرسم والدقة
plt.figure(figsize=(8, 4), dpi=100)
# رسم البيانات
plt.plot(
df_bike["timestamp"],
df_bike["count"],
color="green",
marker="o",
linestyle="-",
linewidth=1,
markersize=3,
)
plt.title("Anzahl der Fahrräder nach Datum", fontsize=16)
plt.xlabel("Datum", fontsize=12)
plt.ylabel("Geteilte Fahrräder", fontsize=12)
plt.grid(True, linestyle="--", alpha=0.6)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# pd.set_option("display.max_rows", None)
start_date = "2015-12-24"
end_date = "2016-01-05"
filtered_data = df_bike[
(df_bike["timestamp"] >= start_date) & (df_bike["timestamp"] <= end_date)
]
selected_data = filtered_data[["timestamp", "count"]]
selected_data
| timestamp | count | |
|---|---|---|
| 8451 | 2015-12-24 00:00:00 | 175 |
| 8452 | 2015-12-24 01:00:00 | 159 |
| 8453 | 2015-12-24 02:00:00 | 104 |
| 8454 | 2015-12-24 03:00:00 | 74 |
| 8455 | 2015-12-24 04:00:00 | 66 |
| ... | ... | ... |
| 8735 | 2016-01-04 20:00:00 | 614 |
| 8736 | 2016-01-04 21:00:00 | 397 |
| 8737 | 2016-01-04 22:00:00 | 293 |
| 8738 | 2016-01-04 23:00:00 | 174 |
| 8739 | 2016-01-05 00:00:00 | 93 |
289 rows × 2 columns
4.3. One-hot encoding¶
Da wir nicht wissen, welcher Code zu welcher Jahreszeit gehört, noch welcher Code zu welchem Wetter gehört, ist die Codierung beider Attribute in einer One-Hot-Codierung die beste Option. Die Modelle können sowohl mit One-Hot-Codierung als auch ohne One-Hot-Codierung trainiert werden, um zu bestimmen, welche Option bessere Ergebnisse liefert.
df_bike.reset_index(drop=True, inplace=True)
df_bike
| timestamp | count | temp | temp_feels_like | humidity | wind_speed | weather_code | is_holiday | is_weekend | season | ... | month | time | day_of_week | season_name | day | n_day | n_month | n_hour | n_day_of_week | n_day_of_year | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2015-01-04 00:00:00 | 182 | 3.0 | 2.0 | 93.0 | 6.0 | 3.0 | 0.0 | 1.0 | 3.0 | ... | January | 00:00:00 | Sunday | Winter | 2015-01-04 | 4 | 1 | 0 | 6 | 4 |
| 1 | 2015-01-04 01:00:00 | 138 | 3.0 | 2.5 | 93.0 | 5.0 | 1.0 | 0.0 | 1.0 | 3.0 | ... | January | 01:00:00 | Sunday | Winter | 2015-01-04 | 4 | 1 | 1 | 6 | 4 |
| 2 | 2015-01-04 02:00:00 | 134 | 2.5 | 2.5 | 96.5 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 | ... | January | 02:00:00 | Sunday | Winter | 2015-01-04 | 4 | 1 | 2 | 6 | 4 |
| 3 | 2015-01-04 03:00:00 | 72 | 2.0 | 2.0 | 100.0 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 | ... | January | 03:00:00 | Sunday | Winter | 2015-01-04 | 4 | 1 | 3 | 6 | 4 |
| 4 | 2015-01-04 04:00:00 | 47 | 2.0 | 0.0 | 93.0 | 6.5 | 1.0 | 0.0 | 1.0 | 3.0 | ... | January | 04:00:00 | Sunday | Winter | 2015-01-04 | 4 | 1 | 4 | 6 | 4 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 17402 | 2017-01-03 19:00:00 | 1042 | 5.0 | 1.0 | 81.0 | 19.0 | 3.0 | 0.0 | 0.0 | 3.0 | ... | January | 19:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 19 | 1 | 3 |
| 17403 | 2017-01-03 20:00:00 | 541 | 5.0 | 1.0 | 81.0 | 21.0 | 4.0 | 0.0 | 0.0 | 3.0 | ... | January | 20:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 20 | 1 | 3 |
| 17404 | 2017-01-03 21:00:00 | 337 | 5.5 | 1.5 | 78.5 | 24.0 | 4.0 | 0.0 | 0.0 | 3.0 | ... | January | 21:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 21 | 1 | 3 |
| 17405 | 2017-01-03 22:00:00 | 224 | 5.5 | 1.5 | 76.0 | 23.0 | 4.0 | 0.0 | 0.0 | 3.0 | ... | January | 22:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 22 | 1 | 3 |
| 17406 | 2017-01-03 23:00:00 | 139 | 5.0 | 1.0 | 76.0 | 22.0 | 2.0 | 0.0 | 0.0 | 3.0 | ... | January | 23:00:00 | Tuesday | Winter | 2017-01-03 | 3 | 1 | 23 | 1 | 3 |
17407 rows × 21 columns
columns_to_encode = ["weather_code", "season"]
encoder_weather = OneHotEncoder(sparse=False)
encoder_weather.fit(df_bike[["weather_code"]])
encoded_weather = encoder_weather.transform(df_bike[["weather_code"]])
encoded_weather_df = pd.DataFrame(
encoded_weather, columns=encoder_weather.get_feature_names_out(["weather_code"])
)
encoded_weather_df
| weather_code_1.0 | weather_code_2.0 | weather_code_3.0 | weather_code_4.0 | weather_code_7.0 | weather_code_10.0 | weather_code_26.0 | |
|---|---|---|---|---|---|---|---|
| 0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 1 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 2 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 3 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 4 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 17402 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 17403 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
| 17404 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
| 17405 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
| 17406 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
17407 rows × 7 columns
encoder_season = OneHotEncoder(sparse=False)
encoder_season.fit(df_bike[["season"]])
encoded_season = encoder_season.transform(df_bike[["season"]])
encoded_season_df = pd.DataFrame(
encoded_season, columns=encoder_season.get_feature_names_out(["season"])
)
encoded_season_df
| season_0.0 | season_1.0 | season_2.0 | season_3.0 | |
|---|---|---|---|---|
| 0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 1 | 0.0 | 0.0 | 0.0 | 1.0 |
| 2 | 0.0 | 0.0 | 0.0 | 1.0 |
| 3 | 0.0 | 0.0 | 0.0 | 1.0 |
| 4 | 0.0 | 0.0 | 0.0 | 1.0 |
| ... | ... | ... | ... | ... |
| 17402 | 0.0 | 0.0 | 0.0 | 1.0 |
| 17403 | 0.0 | 0.0 | 0.0 | 1.0 |
| 17404 | 0.0 | 0.0 | 0.0 | 1.0 |
| 17405 | 0.0 | 0.0 | 0.0 | 1.0 |
| 17406 | 0.0 | 0.0 | 0.0 | 1.0 |
17407 rows × 4 columns
df_bike = pd.concat(
[df_bike, encoded_weather_df, encoded_season_df],
axis=1,
)
df_bike
| timestamp | count | temp | temp_feels_like | humidity | wind_speed | weather_code | is_holiday | is_weekend | season | ... | weather_code_2.0 | weather_code_3.0 | weather_code_4.0 | weather_code_7.0 | weather_code_10.0 | weather_code_26.0 | season_0.0 | season_1.0 | season_2.0 | season_3.0 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2015-01-04 00:00:00 | 182 | 3.0 | 2.0 | 93.0 | 6.0 | 3.0 | 0.0 | 1.0 | 3.0 | ... | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 1 | 2015-01-04 01:00:00 | 138 | 3.0 | 2.5 | 93.0 | 5.0 | 1.0 | 0.0 | 1.0 | 3.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 2 | 2015-01-04 02:00:00 | 134 | 2.5 | 2.5 | 96.5 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 3 | 2015-01-04 03:00:00 | 72 | 2.0 | 2.0 | 100.0 | 0.0 | 1.0 | 0.0 | 1.0 | 3.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 4 | 2015-01-04 04:00:00 | 47 | 2.0 | 0.0 | 93.0 | 6.5 | 1.0 | 0.0 | 1.0 | 3.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 17402 | 2017-01-03 19:00:00 | 1042 | 5.0 | 1.0 | 81.0 | 19.0 | 3.0 | 0.0 | 0.0 | 3.0 | ... | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 17403 | 2017-01-03 20:00:00 | 541 | 5.0 | 1.0 | 81.0 | 21.0 | 4.0 | 0.0 | 0.0 | 3.0 | ... | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 17404 | 2017-01-03 21:00:00 | 337 | 5.5 | 1.5 | 78.5 | 24.0 | 4.0 | 0.0 | 0.0 | 3.0 | ... | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 17405 | 2017-01-03 22:00:00 | 224 | 5.5 | 1.5 | 76.0 | 23.0 | 4.0 | 0.0 | 0.0 | 3.0 | ... | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 17406 | 2017-01-03 23:00:00 | 139 | 5.0 | 1.0 | 76.0 | 22.0 | 2.0 | 0.0 | 0.0 | 3.0 | ... | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
17407 rows × 32 columns
4.4 Entfernen redundanter Daten¶
df_bike_modified = df_bike.drop(
[
"timestamp",
"temp_feels_like",
"weather_code",
"season",
"day_of_week",
"month",
"season_name",
"day",
"time",
"is_weekend",
# "count",
],
axis=1,
)
df_bike_modified.head()
| count | temp | humidity | wind_speed | is_holiday | year | n_day | n_month | n_hour | n_day_of_week | ... | weather_code_2.0 | weather_code_3.0 | weather_code_4.0 | weather_code_7.0 | weather_code_10.0 | weather_code_26.0 | season_0.0 | season_1.0 | season_2.0 | season_3.0 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 182 | 3.0 | 93.0 | 6.0 | 0.0 | 2015 | 4 | 1 | 0 | 6 | ... | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 1 | 138 | 3.0 | 93.0 | 5.0 | 0.0 | 2015 | 4 | 1 | 1 | 6 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 2 | 134 | 2.5 | 96.5 | 0.0 | 0.0 | 2015 | 4 | 1 | 2 | 6 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 3 | 72 | 2.0 | 100.0 | 0.0 | 0.0 | 2015 | 4 | 1 | 3 | 6 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 4 | 47 | 2.0 | 93.0 | 6.5 | 0.0 | 2015 | 4 | 1 | 4 | 6 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
5 rows × 22 columns
df_bike_modified.columns
Index(['count', 'temp', 'humidity', 'wind_speed', 'is_holiday', 'year',
'n_day', 'n_month', 'n_hour', 'n_day_of_week', 'n_day_of_year',
'weather_code_1.0', 'weather_code_2.0', 'weather_code_3.0',
'weather_code_4.0', 'weather_code_7.0', 'weather_code_10.0',
'weather_code_26.0', 'season_0.0', 'season_1.0', 'season_2.0',
'season_3.0'],
dtype='object')
Section 5. Vorhersagemodelle¶
- Data splitting
X = df_bike_modified.drop(["count"], axis=1)
y = df_bike_modified["count"]
- Attributes in data (x) are scaled
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
5.1 Statistical Models¶
5.1.1 Linear Regression + RandomForest Model¶
def custom_rmse(y_true, y_pred):
mse = mean_squared_error(y_true, y_pred)
return abs(mse) ** 0.5
scorers = {
"MSE": make_scorer(mean_squared_error, greater_is_better=False),
"MAE": make_scorer(mean_absolute_error, greater_is_better=False),
"R-squared": make_scorer(
r2_score, greater_is_better=False
), # Greater is better for R-squared
"RMSE": make_scorer(custom_rmse, greater_is_better=False),
}
# Define the models to test
models = {
"LinearRegression": LinearRegression(),
"RandomForest": RandomForestRegressor(random_state=42),
}
# Initialize a DataFrame to store the results
results = []
# Test each algorithm
for model_name, model in models.items():
for metric_name, scorer in scorers.items():
start_time = time.time()
# Then, estimate the performance
scores = -cross_val_score(model, X_train_scaled, y_train, cv=5, scoring=scorer)
end_time = round(time.time() - start_time, 3)
mean_score = round(scores.mean(), 4)
std_score = round(scores.std(), 4)
results.append([model_name, metric_name, mean_score, std_score, end_time])
# Create a DataFrame from the results
columns = ["Algorithm", "Metric", "Mean Score", "Std Score", "Execution Time (s)"]
results_df = pd.DataFrame(results, columns=columns)
# Print the results
print(results_df)
Algorithm Metric Mean Score Std Score Execution Time (s) 0 LinearRegression MSE 786982.4025 45980.1447 0.045 1 LinearRegression MAE 646.6316 16.3621 0.038 2 LinearRegression R-squared 0.3201 0.0185 0.041 3 LinearRegression RMSE 886.7421 25.9023 0.039 4 RandomForest MSE 39235.4922 1527.3812 87.777 5 RandomForest MAE 113.6560 1.8043 80.355 6 RandomForest R-squared 0.9660 0.0020 85.433 7 RandomForest RMSE 198.0423 3.8400 83.310
Algorithm Metric Mean Score Std Score Execution Time (s)
0 LinearRegression RMSLE 0.1359 0.0021 0.068 1 LinearRegression MSE 0.8568 0.0208 0.069 2 LinearRegression MAE 0.7196 0.0100 0.064 3 LinearRegression R-squared 0.4752 0.0169 0.066 4 RandomForest RMSLE 0.0372 0.0062 73.428 5 RandomForest MSE 0.0477 0.0053 89.130 6 RandomForest MAE 0.1390 0.0022 81.862 7 RandomForest R-squared 0.9707 0.0034 97.297
النتائج التي تم الحصول عليها تعتمد على القياسات المستخدمة والمشكلة التي تحاول حلها. هنا هو ما يعني كل قياس:
- RMSLE (Root Mean Squared Logarithmic Error): هذا القياس حساس للفروق النسبية بين القيم الحقيقية والمتوقعة، وليس الفروق المطلقة. قيمة أقل تعني أداء أفضل.
- MSE (Mean Squared Error): هذا القياس يعاقب الأخطاء الكبيرة بشكل أكبر من الأخطاء الصغيرة (بسبب التربيع). قيمة أقل تعني أداء أفضل.
- MAE (Mean Absolute Error): هذا القياس يعطي فكرة عن متوسط الأخطاء في التوقعات، بغض النظر عن الاتجاه. قيمة أقل تعني أداء أفضل.
- R-squared: هذا القياس يوفر فكرة عن مدى قرب البيانات للخط المستقيم المُناظَر. قيمة أعلى (أقرب إلى 1) تعني أداء أفضل.
بالنظر إلى نتائجك، يبدو أن خوارزمية "RandomForest" تؤدي بشكل أفضل من "LinearRegression" في جميع القياسات. ومع ذلك، فإنها تستغرق وقتًا أطول بكثير في التدريب.
5.1.2 Optimization of parameters (Grid search)¶
scoring = {
"RMSE": "neg_root_mean_squared_error",
"MAE": "neg_mean_absolute_error",
"R2": "r2",
"Max Error": "max_error",
}
grid_values_lr = {
"fit_intercept": [True, False],
"positive": [True, False], # إضافة معامل positive بدلاً من normalize
}
# قم بإنشاء نموذج الانحدار الخطي
model_lr = LinearRegression()
# قم بإنشاء مثيل GridSearchCV لنموذج الانحدار الخطي
grid_lr = GridSearchCV(
model_lr, param_grid=grid_values_lr, cv=10, scoring=scoring, refit="RMSE"
)
# نفذ عملية البحث عبر الشبكة
grid_lr.fit(X_train_scaled, y_train)
# احصل على أفضل هيئة لنموذج الانحدار الخطي
best_lr_model = grid_lr.best_estimator_
# عرض أفضل هيئة ونتائج البحث
print("Best Linear Regression Model:")
print("Best Parameters:", grid_lr.best_params_)
# قائمة لتخزين النتائج
results = []
# عرض مقاييس الأداء المتعددة وتخزينها في القائمة
for metric_name, scorer in scoring.items():
scores = grid_lr.cv_results_[f"mean_test_{metric_name}"]
mean_score = round(-scores.mean(), 4)
# std_score = round(scores.std(), 4)
results.append(
[
"LinearRegression",
metric_name,
mean_score,
]
)
# عرض النتائج بالشكل المطلوب
for result in results:
print(result)
Best Linear Regression Model:
Best Parameters: {'fit_intercept': False, 'positive': False}
['LinearRegression', 'RMSE', 909.1428]
['LinearRegression', 'MAE', 671.0793]
['LinearRegression', 'R2', -0.2838]
['LinearRegression', 'Max Error', 4060.4663]
إذا كان RMSLE يساوي 0، فهذا يعني أن التنبؤات مطابقة تمامًا للبيانات الفعلية.
from sklearn.model_selection import RandomizedSearchCV
grid_values_rf = {
"n_estimators": [10, 100, 500, 750, 1000],
"max_depth": [5, 9, 15, 30, None],
"min_samples_split": [2, 5, 10],
"min_samples_leaf": [1, 2, 4],
"max_features": ["auto", "sqrt"],
"bootstrap": [True, False],
"random_state": [42],
}
# قم بإنشاء نموذج RandomForestRegressor
rf_model = RandomForestRegressor()
# إنشاء مثيل RandomizedSearchCV لنموذج RandomForestRegressor باستخدام مقياسي RMSE و R-squared
grid_rf = RandomizedSearchCV(
rf_model,
param_distributions=grid_values_rf,
cv=5,
scoring=["r2", "neg_root_mean_squared_error"], # استخدم قائمة المقاييس
n_jobs=-1,
n_iter=100,
refit="neg_root_mean_squared_error", # grid_rf.best_score_ يعيد أفضل قيمة للمقياس الذي تم تحديده كـ refit عند إنشاء
)
# نفذ عملية البحث عبر الشبكة
grid_rf.fit(X_train_scaled, y_train)
# الحصول على أفضل هيئة لنموذج RandomForestRegressor
best_rf_model = grid_rf.best_estimator_
# عرض أفضل هيئة ونتائج البحث للمقاييس المختارة
print("Best RandomForest Model:", best_rf_model)
print("Best Parameters:", grid_rf.best_params_)
print(
"Best R-squared Score:", grid_rf.cv_results_["mean_test_r2"][grid_rf.best_index_]
) # استخدم R-squared
print("Best RMSE Score:", -grid_rf.best_score_) # استخدم الناتج السلبي للمقياس RMSE
Best RandomForest Model: RandomForestRegressor(bootstrap=False, max_depth=30, max_features='sqrt',
n_estimators=750, random_state=42)
Best Parameters: {'random_state': 42, 'n_estimators': 750, 'min_samples_split': 2, 'min_samples_leaf': 1, 'max_features': 'sqrt', 'max_depth': 30, 'bootstrap': False}
Best R-squared Score: 0.8641685995724752
Best RMSE Score: 396.35537684637404
Best RandomForest Model: RandomForestRegressor(bootstrap=False, max_features='sqrt', n_estimators=750, random_state=42) Best Parameters: {'random_state': 42, 'n_estimators': 750, 'min_samples_split': 2, 'min_samples_leaf': 1, 'max_features': 'sqrt', 'max_depth': None, 'bootstrap': False} Best R-squared Score: 0.8639175940759671 Best RMSE Score: -0.8639175940759671
Best RandomForest Model: RandomForestRegressor(bootstrap=False, max_features='sqrt', min_samples_split=5, n_estimators=1000, random_state=42) Best Parameters: {'random_state': 42, 'n_estimators': 1000, 'min_samples_split': 5, 'min_samples_leaf': 1, 'max_features': 'sqrt', 'max_depth': None, 'bootstrap': False} Best Score: 0.8563188282391103
Best RandomForest Model: RandomForestRegressor(bootstrap=False, max_depth=9, max_features='sqrt', min_samples_leaf=5, random_state=42) Best Parameters: {'n_estimators': 100, 'min_samples_leaf': 5, 'max_features': 'sqrt', 'max_depth': 9, 'bootstrap': False} Best Score: 0.6745014992501922
Best RandomForest Model (RMSE): RandomForestRegressor(bootstrap=False, max_depth=5, max_features='sqrt', min_samples_leaf=50, n_estimators=10, random_state=42) Best Parameters (RMSE): {'bootstrap': False, 'max_depth': 5, 'max_features': 'sqrt', 'min_samples_leaf': 50, 'n_estimators': 10} Best RMSE Score: 775.8112430562294
Section 6. Results¶
def plot_scores(model, X_test, y_test):
# التحقق من أن عدد الصفوف في y_test متساوٍ لعدد الصفوف في X_test
assert y_test.shape[0] == X_test.shape[0]
predictions = model.predict(X_test)
actual_values = y_test
# حساب وعرض خطأ الجذر التربيعي لمتوسط الأخطاء المربعية (RMSE)
rmse = np.sqrt(mean_squared_error(actual_values, predictions))
print("Root Mean Squared Error (RMSE): ", rmse)
# حساب وعرض الخطأ المطلق المتوسط (MAE)
mae = mean_absolute_error(actual_values, predictions)
print("Mean Absolute Error (MAE): ", mae)
# حساب وعرض معامل التحديد R-squared
r_squared = r2_score(actual_values, predictions)
print("R-squared (Coefficient of Determination): ", r_squared)
# حساب وعرض مقياس الخطأ الأقصى (Max Error)
max_err = max_error(actual_values, predictions)
print("Max Error: ", max_err)
plot_scores(grid_rf.best_estimator_, X_test_scaled, y_test)
Root Mean Squared Error (RMSE): 393.35467056040477 Mean Absolute Error (MAE): 241.63337230608238 R-squared (Coefficient of Determination): 0.8701924777024996 Max Error: 2627.8388148148147
plot_scores(grid_lr.best_estimator_, X_test_scaled, y_test)
Root Mean Squared Error (RMSE): 901.1443479611899 Mean Absolute Error (MAE): 660.3401925389475 R-squared (Coefficient of Determination): 0.3187289031567806 Max Error: 4113.699101001589